package cn.com.fuhuitong.base

import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Observer
import java.lang.ref.WeakReference
import java.lang.reflect.Field
import java.lang.reflect.Method


class SafeMutableLiveData<T> : MutableLiveData<T>() {
    private var lastLifecycleOwner: WeakReference<LifecycleOwner>? = null

    fun safeObserve(owner: LifecycleOwner, observer: Observer<T>) {
        lastLifecycleOwner?.get()?.let {
            removeObservers(it)
        }
        lastLifecycleOwner = WeakReference(owner)
        observe(owner, observer)
//        hook(observer)
    }

    override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {
        super.observe(owner, observer)
        hook(observer)
    }

    private fun hook(observer: Observer<in T>) {
        val liveDataClass = LiveData::class.java
        try {
            val mObservers: Field = liveDataClass.getDeclaredField("mObservers")
            mObservers.setAccessible(true)
            val mObserversObject: Any = mObservers.get(this) ?: return
            val mObserversClass: Class<*> = mObserversObject.javaClass
            val methodGet: Method = mObserversClass.getDeclaredMethod("get", Any::class.java)
            methodGet.setAccessible(true)
            val entry: Any = methodGet.invoke(mObserversObject, observer) as? Map.Entry<*, *>
                ?: return
            val lifecycleBoundObserver =
                (entry as Map.Entry<*, *>).value!!
            val observerWrapper =
                lifecycleBoundObserver.javaClass.superclass
                    ?: return
            val mLastVersionField: Field = observerWrapper.getDeclaredField("mLastVersion")
            mLastVersionField.setAccessible(true)
            val versionMethod: Method = liveDataClass.getDeclaredMethod("getVersion")
            versionMethod.setAccessible(true)
            val version: Any = versionMethod.invoke(this)
            mLastVersionField.set(lifecycleBoundObserver, version)
            mObservers.setAccessible(false)
            methodGet.setAccessible(false)
            mLastVersionField.setAccessible(false)
            versionMethod.setAccessible(false)
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

}